题目:给定数组arr=[2,1,5,3,6,4,8,9,7],返回最长递增子序列,即[1,3,4,8,9]。
要求:若arr长度为N,时间复杂度为O(NlogN)。
实现
方法一:时间复杂度为O(N^2)
步骤一:生成长度为N的数组dp,dp[i]表示以arr[i]这个数结尾的情况下,arr[0,…i]中的最大递增子序列长度。
- 对于第一个数dp[0]=1,接下来一次算出每个位置的数结尾的情况下的最大递增子序列长度。
- 对于dp[i],它以arr[i]结尾,arr[0,…i-1]中比arr[i]小的数都可以作为arr[i]的倒数第二个节点,选择以那个数(如arr[j])结尾的最大递增子序列(如dp[j])最大的那个数作为倒数第二个数,即dp[i] = max{dp[j]+1},0<=j<i,arr[j]<arr[i](由于说了是递增,不是非减,所以arr[j]与arr[i]之间没有等号)。
- 若arr[0,…i-1]中,没有比arr[i]小的数,则令dp[i]=1,即其最大递增子序列就是自身。
结果为dp=[1,1,2,2,3,3,4,5,4]。
步骤二:根据dp数组得到最长递增子序列
- 遍历dp数组,找到最大值(即最长递增子序列的长度)及位置。本例中最大值为5,位置为7。
- 从arr[7]开始从右向左遍历。如果对于某一位置i,有arr[i]<arr[7] && dp[i]=dp[7]-1,则arr[i]可作为最长递增子序列的倒数第二个数,本例中为arr[6]=8。
- 然后继续从位置6向左遍历,直到所有数据都找出来。
1 | import java.util.concurrent.SynchronousQueue; |
1 | //Test |
输出:
dp[i]保存的是以arr[i]结尾的最长递增子序列的长度:
1 1 2 2 3 3 4 5 4
最长递增子序列为:
1 3 4 8 9
方法二:利用二分查找对生成dp数组的过程进行优化,时间复杂度为O(NlogN)